#include "libCache.h"
static uint32_t ultimaPosicion = 0;
extern size_t cacheSize;
extern size_t chunkSize;
extern uint8_t administracion;
extern uint8_t algoritmoEleccion;
extern uint8_t algoritmoReemplazo;

memCache_t* inicializarCache(uint32_t varSize) {
	memCache_t* vectorCache;
	vectorCache = malloc((cacheSize / chunkSize) * sizeof(memCache_t));
	uint32_t i;
	for (i = 0; i < (varSize / chunkSize); i++) {
		vectorCache[i].codBuddy = 0;
		vectorCache[i].estado = 'L';
		vectorCache[i].enUso = 0;
		memset(vectorCache[i].key, '\0', 42);
		vectorCache[i].tiempo.tv_sec = 0; //TODO MODIFICADO
		vectorCache[i].tiempo.tv_usec = 0;

		//printf("posicion: [%d]-- estado: [%c] -- codBuddy:[%d] -- Key:[%s]\n", i, vectorCache[i].estado, vectorCache[i].codBuddy, vectorCache[i].key);
	}
	//printf("Termine de inicializar el vector de la cache\n");
	return vectorCache;
}

uint32_t cantidadConMismoEstadoYKey(memCache_t* vectorCache, uint32_t* pos, char estado, char* key, size_t nkey) {
	uint32_t cantidad = 0;
	while ((*pos < (cacheSize / chunkSize)) && (vectorCache[*pos].estado == estado) && (compararKeys(vectorCache[*pos].key, vectorCache[*pos].nkey, key, nkey))) {
		//	printf("Key 1: [%s] . Size: [%d]\n", vectorCache[*pos].key, vectorCache[*pos].nkey);
		//printf("Key 2 : [%s] . Size [%d]\n", key, nkey);
		(*pos)++;
		cantidad++;
	}
	return cantidad;
}

uint8_t compararKeys(char* key1, size_t nkey1, char*key2, size_t nkey2) {
	if (strcmp(key1, key2) == 0 && nkey1 == nkey2) {
		return 1;
	} else {
		return 0;
	}
}

uint32_t cantidadConMismoEstadoYCodBuddy(memCache_t* vectorCache, uint32_t *pos, char estado, uint32_t codBuddy) {
	uint32_t cantidad = 0;
	while (*pos < (cacheSize / chunkSize) && vectorCache[*pos].estado == estado && vectorCache[*pos].codBuddy == codBuddy) {
		(*pos)++;
		cantidad++;
	}
	return cantidad;
}

uint32_t cantidadConMismoEstado(memCache_t* cache, uint32_t* pos, char estado, uint8_t enUso) {
	uint32_t cantidad = 0;
	while (*pos < cacheSize / chunkSize && cache[*pos].estado == estado && cache[*pos].enUso == enUso) {
		(*pos)++;
		cantidad++;
	}
	return cantidad;
}

int32_t worstFit(memCache_t *memoria, uint32_t requiredChunks) {
	//printf("----------------------------------------------------------------------------------------------------\n");
	//printf(">> Inicio la busqueda de un lugar libre con WORST FIT.\n");
	//printf("Necesito [%d] bytes\n", requiredChunks);
	uint32_t pos = 0;
	int32_t retorno = -1;
	int32_t tamanio = 0;
	uint32_t posAnt = 0;
	while (pos < (cacheSize / chunkSize)) {
		//	printf("Reviso la posicion [%d].\n", pos);
		char estado = memoria[pos].estado;
		uint8_t enUso = memoria[pos].enUso;
		posAnt = pos;
		tamanio = cantidadConMismoEstado(memoria, &pos, memoria[pos].estado, memoria[pos].enUso);
		//printf("Estado: [%c]\n", estado);
		//printf("Cantidad con mismo estado: [%d]\n", tamanio);
		//printf("Retorno: [%d]\n", retorno);
		if (tamanio >= requiredChunks)
			//	printf("tamanio >= requiredChunks\n");
			if (tamanio > retorno)
				//	printf("tamanio > retorno\n");
				if ((estado == 'L') && tamanio >= requiredChunks && enUso == 0 && tamanio > retorno) {
					//	printf("La posicion [%d] contenia [%d] chunks, y como solo necesito [%d] chunks es una posicion valida.\n", posAnt, tamanio, requiredChunks);
					retorno = posAnt;
				}
	}
	//printf("La posicion elegida finalmente es la [%d].\n", posAnt);
	/*
	 * tratar el -1 como ERROR_NO_HAY_ESPACIO
	 */
	//printf("----------------------------------------------------------------------------------------------------\n");
	return retorno;

}

/*char* leerCache(char* cache, uint32_t inicio, uint32_t tamanio) {
 estar atentos a memcached y los centinelas
 char* infoCache = malloc(tamanio);
 memset(infoCache, '\0', tamanio + 1);
 memcpy(infoCache, cache + inicio, tamanio);
 return infoCache;
 }*/

void escribirCache(char* cache, uint32_t inicio, uint32_t tamanio, const char* info) {
	memcpy(cache + inicio, info, tamanio);
	return;
}

int64_t buscarPrimerLibre(memCache_t *cache) {
	int64_t libre = -1;
	uint32_t pos = 0;
	uint8_t encontrado = 0;
	while ((pos < cacheSize / chunkSize) && (!encontrado)) {
		if (cache[pos].estado == 'L') {
			encontrado = 1;
			libre = pos;
		}
		pos++;
	}
	return libre;

}

void swapearCache(char* infoCache, uint32_t posAux, uint32_t posLibre) {
	/*char* info = leerCache(infoCache, posAux * chunkSize, chunkSize);
	 escribirCache(infoCache, posLibre * chunkSize, chunkSize, info);
	 free(info);*/
	memcpy(infoCache + (posLibre * chunkSize), infoCache + (posAux * chunkSize), chunkSize);
}

void compactarCache(char* infoCache, memCache_t* estructuraCache) {
	uint32_t posLibre;
	uint32_t i;
	loguearDatos("INFO", time(NULL), "RC", (uint32_t) getpid(), (uint32_t) pthread_self(), "Se compacta la caché", NIVEL_LOG_OBLIGATORIO);
	for (i = 0; i < cacheSize / chunkSize; i++) {
		//printf("<compactarCache> INTENTO BLOQUEAR CHUNK %d\n", i);
		//pthread_rwlock_wrlock(&(estructuraCache[i].semChunk));
		pthread_mutex_lock(&(estructuraCache[i].mutexChunk));
		//printf("<compactarCache> BLOQUEÉ CHUNK %d\n", i);
	}
	if ((posLibre = buscarPrimerLibre(estructuraCache)) != -1) {
		uint32_t posAux = posLibre;
		while (posAux < (cacheSize / chunkSize)) {
			if (estructuraCache[posAux].estado == 'O') {
				estructuraCache[posLibre] = estructuraCache[posAux];
				estructuraCache[posAux].estado = 'L';
				swapearCache(infoCache, posAux, posLibre);
				posLibre = buscarPrimerLibre(estructuraCache);
			}
			posAux++;
		}
	}
	for (i = 0; i < cacheSize / chunkSize; i++) {
		//printf("<compactarCache> INTENTO DESBLOQUEAR CHUNK %d\n", i);
		//pthread_rwlock_unlock(&(estructuraCache[i].semChunk));
		pthread_mutex_unlock(&(estructuraCache[i].mutexChunk));
		//printf("<compactarCache> DESBLOQUEÉ CHUNK %d\n", i);
	}
}

int32_t NextFit(memCache_t *memoria, uint32_t requiredSize) {
	//printf("Ultima Posicion: [%d]\n", ultimaPosicion);
	uint32_t posAnt = ultimaPosicion;
	uint32_t ultimaPosAux = ultimaPosicion;
	uint32_t tamanio;

	while (ultimaPosicion < (cacheSize / chunkSize)) {

		tamanio = cantidadConMismoEstado(memoria, &ultimaPosicion, memoria[ultimaPosicion].estado, memoria[ultimaPosicion].enUso);
		if (tamanio >= requiredSize && memoria[posAnt].estado == 'L' && memoria[posAnt].enUso == 0) {
			return posAnt;
		}
		posAnt = ultimaPosicion;
	}
	//printf("Llegue al final de la cache sin encontrar\n");
	ultimaPosicion = 0;
	posAnt = 0;
	while (ultimaPosicion < ultimaPosAux) {
		tamanio = cantidadConMismoEstado(memoria, &ultimaPosicion, memoria[ultimaPosicion].estado, memoria[ultimaPosicion].enUso);
		if (tamanio >= requiredSize && memoria[posAnt].estado == 'L' && memoria[posAnt].enUso == 0) {
			//printf("Devuelvo en el segundo while [%d]\n", ultimaPosicion);
			return posAnt;
		}
		posAnt = ultimaPosicion;
	}
	ultimaPosicion = ultimaPosAux;
	//printf("No se encontro espacio\n");
	return -1;
}

void cargarCache(uint32_t pos, uint32_t cantChunks, size_t sizeKey, const char* key, CUCA_diccionario_t diccionario, const char* value, size_t sizeData) {
	//TODO LE AGREGUE EL TAMANIO DE LA KEY, PARA EVITAR ESCRIBIR BASURA
	uint32_t i;
	struct timeval tiempo;
	gettimeofday(&tiempo, NULL);
	//printf("<cargarCache> segundos: %d\n<cargarCache> microsegundos: %d\n\n", (uint32_t) tiempo.tv_sec, (uint32_t) tiempo.tv_usec);
	for (i = pos; i < pos + cantChunks; i++) {
		diccionario.vectorCache[i].enUso = 1;
		diccionario.vectorCache[i].estado = 'O';
		memset(&(diccionario.vectorCache[i].key), '\0', 42);
		memcpy(&(diccionario.vectorCache[i].key), key, sizeKey);
		//printf("Key: [%s]\n", (char*) diccionario.vectorCache[i].key);
		diccionario.vectorCache[i].nkey = sizeKey;
		//printf("nkey: [%d]\n", diccionario.vectorCache[i].nkey);
		diccionario.vectorCache[i].ndata = sizeData;
		//printf("nData: [%d]\n", diccionario.vectorCache[i].ndata);
		diccionario.vectorCache[i].tiempo = tiempo;
	}
	escribirCache(diccionario.cache, pos * chunkSize, cantChunks * chunkSize, value);
}

void cargarKey(uint32_t pos, uint32_t cantChunks, size_t sizeKey, const char* key, CUCA_diccionario_t diccionario, size_t sizeData) {
	uint32_t i;
	struct timeval tiempo;
	gettimeofday(&tiempo, NULL);
	//printf("<cargarKey> segundos: %d\n<cargarKey> microsegundos: %d\n\n", (uint32_t) tiempo.tv_sec, (uint32_t) tiempo.tv_usec);
	for (i = pos; i < cantChunks + pos; i++) {
		diccionario.vectorCache[i].enUso = 1;
		//printf("<cargarKey> INTENTO BLOQUEAR CHUNK %d\n", i);
		//pthread_rwlock_wrlock(&(diccionario.vectorCache[i].semChunk));
		pthread_mutex_lock(&(diccionario.vectorCache[i].mutexChunk));
		//printf("<cargarKey> BLOQUEÉ CHUNK %d\n",i);
		memset(&(diccionario.vectorCache[i].key), '\0', 42);
		memcpy(&(diccionario.vectorCache[i].key), key, sizeKey);
		diccionario.vectorCache[i].nkey = sizeKey;
		diccionario.vectorCache[i].ndata = sizeData;
		diccionario.vectorCache[i].tiempo = tiempo;
	}
}

void eliminarParticion(memCache_t* cache) {
	//printf("<eliminarParticion> \n");
	uint32_t pos = 0;
	uint32_t posAnt = 0;
	while (pos < cacheSize / chunkSize) {
		if (cache[posAnt].estado == 'L' && cache[pos].estado == 'O') {
			posAnt = pos;
		}
		if (cache[pos].estado == 'O' && (esMenorElTiempo(cache[pos].tiempo, cache[posAnt].tiempo)) && cache[pos].enUso == 0) {
			posAnt = pos;
		}
		pos++;
	}
	char* key = cache[posAnt].key;
	size_t nkey = cache[posAnt].nkey;
	uint32_t posAntAUnir = posAnt;
	char victima[5];
	memset(victima, '\0', 5);
	//printf("Algoritmo de reemplazo: %d\n", algoritmoReemplazo);
	if (algoritmoReemplazo == ALGORITMO_LRU) {
		strcpy(victima, "LRU");
	} else if (algoritmoReemplazo == ALGORITMO_FIFO) {
		strcpy(victima, "FIFO");
	}
	//printf("Algoritmo de Reemplazo: %s\n", victima);
	if (victima != '\0') {
		loguearDatosTemplate("DEBUG", time(NULL), "RC", getpid(), pthread_self(), NIVEL_LOG_OBLIGATORIO, "Eliminar Particion - Key [%s] - Algoritmo de reemplazo [%s]", key, victima);
		while (posAnt < (cacheSize / chunkSize) && compararKeys(key, nkey, cache[posAnt].key, cache[posAnt].nkey) && cache[posAnt].enUso == 0) {
			cache[posAnt].estado = 'L';
			posAnt++;
		}
		if (posAntAUnir < (cacheSize / chunkSize) && administracion == ADMINISTRACION_BUDDY) {
			cache[posAntAUnir].enUso = 0;
			intentarUnirBuddies(cache, posAntAUnir);
		}
	} else {
		//printf("Cagaste Evar\n");
	}
}

void eliminarParticionNextFit(memCache_t* cache) {
	//printf("<eliminarParticionNextFit> \n");
	uint32_t posAnt = ultimaPosicion;
	uint32_t posInicio = ultimaPosicion;
	while (ultimaPosicion < (cacheSize / chunkSize)) {
		if (cache[posAnt].estado == 'L' && cache[ultimaPosicion].estado == 'O') {
			posAnt = ultimaPosicion;
		}
		if (cache[ultimaPosicion].estado == 'O' && (esMenorElTiempo(cache[ultimaPosicion].tiempo, cache[posAnt].tiempo)) && cache[ultimaPosicion].enUso == 0) {
			posAnt = ultimaPosicion;
		}
		ultimaPosicion++;
	}
	ultimaPosicion = 0;
	while (ultimaPosicion < posInicio) {
		if (cache[posAnt].estado == 'L' && cache[ultimaPosicion].estado == 'O') {
			posAnt = ultimaPosicion;
		}
		if (cache[ultimaPosicion].estado == 'O' && esMenorElTiempo(cache[ultimaPosicion].tiempo, cache[posAnt].tiempo) && cache[ultimaPosicion].enUso == 0) {
			posAnt = ultimaPosicion;
		}
		ultimaPosicion++;
	}
	char* key = cache[posAnt].key;
	size_t nkey = cache[posAnt].nkey;
	char victima[5];
	memset(victima, '\0', 5);
	if (algoritmoReemplazo == ALGORITMO_LRU) {
		strcpy(victima, "LRU");
	} else {
		strcpy(victima, "FIFO");
	}
	loguearDatosTemplate("DEBUG", time(NULL), "RC", getpid(), pthread_self(), NIVEL_LOG_OBLIGATORIO, "Eliminar Particion - Key [%s] - Algoritmo de reemplazo [%s]", key, victima);

	posInicio = posAnt;
	ultimaPosicion = posAnt;
	while (ultimaPosicion < cacheSize / chunkSize && compararKeys(key, nkey, cache[ultimaPosicion].key, cache[ultimaPosicion].nkey) && cache[ultimaPosicion].enUso == 0) {
		cache[ultimaPosicion].estado = 'L';
		ultimaPosicion++;
	}
	if (posInicio < (cacheSize / chunkSize) && administracion == ADMINISTRACION_BUDDY) {
		intentarUnirBuddies(cache, posInicio);
	}
}

int64_t buddySystem(memCache_t* memoria, uint32_t reqSize) {
	if (!esPotencia(reqSize, 2)) {
		reqSize = potenciaDe2Proxima(reqSize);
	}
	uint32_t auxRequiredSize = reqSize;
	if (reqSize < chunkSize)
		auxRequiredSize = chunkSize;
	uint8_t encontrado = 0;
	uint32_t pos;
	uint32_t cantidad = 0;
	char estadoAnt;
	uint8_t enUso;
	//printf("Bienvenido al algoritmo Buddy System\n");
	//printf("Se intentaran almacenar: %d bytes\n", reqSize);
	for (pos = 0; pos < cacheSize / chunkSize && !encontrado;) {
		estadoAnt = memoria[pos].estado;
		enUso = memoria[pos].enUso;
		cantidad = cantidadConMismoEstadoYCodBuddy(memoria, &pos, memoria[pos].estado, memoria[pos].codBuddy);
		//printf("Cantidad con mismo estado y codigo buddy: [%d]\n", cantidad);
		if (cantidad * chunkSize >= reqSize && estadoAnt == 'L' && !enUso)
			encontrado = 1;
	}
	if (encontrado) {
		//printf("Se encontró lugar\n");
		pos -= cantidad;
		//printf("la posicion donde arranco es: [%d]\n", pos);
		while ((cantidad * chunkSize) > auxRequiredSize) {
			//	printf("cantidad * chunksize > reqsize? [%d]>[%d]\n", cantidad * chunkSize, auxRequiredSize);
			if (crearBuddies(memoria, memoria[pos].codBuddy, pos) == DIVIDIR_PARTICION_MINIMA) {
				break;
			}
			cantidad = cantidadConMismoCodigoBuddy(memoria, pos);
			//printf("[%d]\n", cantidad * chunkSize);
			//printf("Cantidad despues del while: [%d]\n", cantidad);
		}

	} else {
		//printf("No se pudo encontrar lugar\n");
		if (!encontrado && memoria[0].codBuddy == 0) {
			if (algoritmoEleccion == ALGORITMO_NEXT_FIT) {
				eliminarParticionNextFit(memoria);
			} else {
				eliminarParticion(memoria);
			}
			pos = cantidad;
			encontrado = 1;
		} else {
			while (!encontrado && memoria[0].codBuddy != 0) {
				//printf("Entro en el while de eliminaciòn de un buddy\n");
				if (algoritmoEleccion == ALGORITMO_NEXT_FIT) {
					eliminarParticionNextFit(memoria);
				} else {
					eliminarParticion(memoria);
				}
				for (pos = 0; pos < cacheSize / chunkSize && !encontrado;) {
					estadoAnt = memoria[pos].estado;
					cantidad = cantidadConMismoEstadoYCodBuddy(memoria, &pos, memoria[pos].estado, memoria[pos].codBuddy);
					//printf("Cantidad con mismo estado y codigo buddy: [%d]\n", cantidad);
					if (cantidad * chunkSize >= reqSize && estadoAnt == 'L')
						encontrado = 1;
				}

			}
		}
		//printf("Termine de borrar.\n");
		//printf("Cantidad: [%d].\n", cantidad);
		//printf("Pos: [%d].\n", pos);
		if (encontrado) {
			pos -= cantidad;
			//printf("Se encontró lugar\n");
			//printf("la posicion donde arranco es: [%d]\n", pos);
			while ((cantidad * chunkSize) > auxRequiredSize) {
				//printf("cantidad * chunksize > reqsize? [%d]>[%d]\n", cantidad * chunkSize, auxRequiredSize);
				if (crearBuddies(memoria, memoria[pos].codBuddy, pos) == DIVIDIR_PARTICION_MINIMA) {
					break;
				}
				cantidad = cantidadConMismoCodigoBuddy(memoria, pos);
				//printf("[%d]\n", cantidad * chunkSize);
				//printf("Cantidad despues del while: [%d]\n", cantidad);
			}

		} else {
			//printf("El dato solicitado es superior al tamaño de la cache.\n");
			return -1;
		}
	}
	return pos;
}

uint32_t cantidadConMismoCodigoBuddy(memCache_t *cache, uint32_t pos) {
	uint32_t i;
	uint32_t codigoBuddy = cache[pos].codBuddy;
	uint32_t contador = 0;
	//printf("Empiezo a contar desde la pos: [%d]\n", pos);
	for (i = pos; cache[i].codBuddy == codigoBuddy && i < cacheSize / chunkSize; i++) {
		contador++;
	}
	return contador;
}

int32_t crearBuddies(memCache_t *cache, uint32_t padre, uint32_t pos) {
	uint32_t cantidad = cantidadConMismoCodigoBuddy(cache, pos);
	uint32_t cantHijo;
	uint16_t contadoraux = 0;
	uint16_t contadoraux2 = 0;
	//printf("Bienvenido a crear Buddies\n");
	if (cantidad != 1) {
		//printf("Divido la cantidad\n");
		//printf("Cantidad: [%d]\n", cantidad);
		cantHijo = cantidad / 2;
		//printf("Cantidad hijo: [%d]\n", cantHijo);
	} else { // TODO aca viene un error porque quiero dividir la menor porción de memoria.
		//printf("Intento dividir la partición mínima\n");
		return DIVIDIR_PARTICION_MINIMA;
	}
	uint32_t i;
	for (i = 0; i < cantHijo; i++) {
		contadoraux++;
		cache[pos + i].codBuddy = (2 * cache[pos + i].codBuddy) + 1;
	}
	for (; i < cantidad; i++) {
		contadoraux2++;
		cache[pos + i].codBuddy = (2 * cache[pos + i].codBuddy) + 2;
	}
	//printf("Salgo del for, contadorAux1 = [%d]--- contadorAux2 = [%d]\n", contadoraux, contadoraux2);
	return 0;
}

/*void unirBuddies(memCache_t *cache, uint32_t pos, uint32_t cantidad) {
 uint32_t i;
 uint32_t codBuddy = ((cache[pos].codBuddy - 1) / 2);
 for (i = pos; i < (pos + cantidad); i++) {
 cache[i].codBuddy = codBuddy;
 }
 }

 int32_t intentarUnirBuddies(memCache_t *cache, uint32_t pos) {
 uint32_t buddy1 = cache[pos].codBuddy;
 if (div(buddy1, 2).rem == 1) {
 uint32_t cant1 = cantidadConMismoCodigoBuddy(cache, pos);
 uint32_t cant2 = cantidadConMismoCodigoBuddy(cache, pos + cant1);
 if (cant1 == cant2 && cache[pos + cant1].estado == 'L') {
 unirBuddies(cache, pos, cant1 + cant2);
 intentarUnirBuddies(cache, pos);
 }
 } else {
 uint32_t cant2 = cantidadConMismoCodigoBuddy(cache, pos);
 uint32_t cant1 = cantidadConMismoCodigoBuddy(cache, pos - cant2);
 if (cant1 == cant2 && cache[pos - cant1].estado == 'L') {
 unirBuddies(cache, pos - cant2, cant1 + cant2);
 intentarUnirBuddies(cache, pos - cant2);
 }
 }
 return 0;
 }*/

ENGINE_ERROR_CODE buscaYBorraWorstFit(memCache_t* cache, char* key, size_t nkey) {
	uint32_t i;
	//printf("Usted quiere borrar la key [%s]\n", key);
	for (i = 0; (i < cacheSize / chunkSize) && !compararKeys(cache[i].key, cache[i].nkey, key, nkey); i++) {
		//	printf("Key almacenada: [%s]\n", cache[i].key);
	}
	if (compararKeys(cache[i].key, cache[i].nkey, key, nkey)) {
		if (administracion == ADMINISTRACION_BUDDY) {
			intentarUnirBuddies(cache, i);
		}
		while ((i < cacheSize / chunkSize) && compararKeys(cache[i].key, cache[i].nkey, key, nkey)) {
			cache[i].estado = 'L';
			memset(cache[i].key, '\0', 42);
			i++;
		}
		return ENGINE_SUCCESS;
	} else {
		return ENGINE_KEY_ENOENT;
	}
}

ENGINE_ERROR_CODE buscaYBorraNextFit(memCache_t* cache, char* key, size_t nkey) {
	uint32_t posInicio = ultimaPosicion;
	//printf("La posicion de inicio es: [%d].\n", posInicio);
	uint8_t encontrado = 0;
	uint32_t pos = (cacheSize / chunkSize) + 1;
	while (ultimaPosicion < cacheSize / chunkSize) {
		//printf("todavía no llegue al final de la cache.\n");
		//printf("UltimaPosii");
		if (compararKeys(cache[ultimaPosicion].key, cache[ultimaPosicion].nkey, key, nkey)) {
			if (ultimaPosicion < pos)
				pos = ultimaPosicion;
			encontrado = 1;
			cache[ultimaPosicion].estado = 'L';
			memset(cache[ultimaPosicion].key, '\0', 42);
		}
		ultimaPosicion++;
	}
	ultimaPosicion = 0;
	while (ultimaPosicion < posInicio) {
		//printf("UltimaPosicion accedida: [%d].\n", ultimaPosicion);
		if (compararKeys(cache[ultimaPosicion].key, cache[ultimaPosicion].nkey, key, nkey)) {
			if (ultimaPosicion < pos)
				pos = ultimaPosicion;
			encontrado = 1;
			cache[ultimaPosicion].estado = 'L';
			memset(cache[ultimaPosicion].key, '\0', 42);
		}
		ultimaPosicion++;
	}
	if (encontrado) {
		if (administracion == ADMINISTRACION_BUDDY) {
			intentarUnirBuddies(cache, pos);
		}
		return ENGINE_SUCCESS;
	} else {
		return ENGINE_KEY_ENOENT;
	}
}

void intentarUnirBuddies(memCache_t* cache, uint32_t posBorrada) {
	uint8_t seUnio = 0;
	uint32_t inicio;
	uint32_t codAnt = cache[posBorrada].codBuddy;
	//printf("Ingresando a intentarUnirBuddies.\n");
	if (cache[posBorrada].codBuddy != 0) {
		if ((div(cache[posBorrada].codBuddy, 2).rem != 0) && (cache[posBorrada + cantidadConMismoCodigoBuddy(cache, posBorrada)].estado == 'L') && (cache[posBorrada + cantidadConMismoCodigoBuddy(cache, posBorrada)].codBuddy - codAnt) == 1) { //Caso 1 borro una posición Impar, su buddy es = i +1
			//printf("Se borro el buddy [%d] (impar) y su amigo [%d] (par) està Libre, se uniran \n", cache[posBorrada].codBuddy, cache[posBorrada + cantidadConMismoCodigoBuddy(cache, posBorrada)].codBuddy);
			seUnio = 1;
			inicio = unirBuddies(cache, posBorrada, cantidadConMismoCodigoBuddy(cache, posBorrada));
		} else if ((div(cache[posBorrada].codBuddy, 2).rem == 0) && (cache[posBorrada - 1].estado == 'L') && (codAnt - cache[posBorrada - 1].codBuddy == 1)) { // Caso 2, posicion par borrada, busca en la anterior (posBorrada-1)
			//printf("Se borro el buddy [%d] (par) y su amigo [%d] (impar) està Libre, se uniran \n", cache[posBorrada].codBuddy, cache[posBorrada - 1].codBuddy);
			seUnio = 1;
			inicio = unirBuddies(cache, (posBorrada - cantidadConMismoCodigoBuddy(cache, posBorrada)), cantidadConMismoCodigoBuddy(cache, posBorrada));
		}
		if (seUnio) {
			intentarUnirBuddies(cache, inicio);
		} else {
			//printf("No se pudieron unir los buddies.\n");
		}
	}
}

uint32_t unirBuddies(memCache_t* cache, uint32_t posInicio, uint32_t tamanio) {
	uint32_t i;
	uint32_t inicio = posInicio;
	//printf("PosInicio: [%d].\n", posInicio);
	//printf("Tamanio: [%d].\n", tamanio);
	//printf("Bienvenido a unirBuddies, tenemos los buddys [%d] y [%d], que seran [%d]\n", cache[posInicio].codBuddy, cache[posInicio + tamanio].codBuddy, (cache[posInicio].codBuddy - 1) / 2);
	for (i = posInicio; i < posInicio + tamanio; i++) {
		cache[i].codBuddy = (cache[i].codBuddy - 1) / 2;
	}
	for (i = posInicio + tamanio; i < posInicio + (2 * tamanio); i++) {
		cache[i].codBuddy = (cache[i].codBuddy - 2) / 2;
	}
	return inicio;
}

uint8_t yaExisteKey(char* key, size_t nkey, CUCA_diccionario_t diccionario) {
	uint32_t i;
	for (i = 0; ((i < cacheSize / chunkSize) && (compararKeys(key, nkey, diccionario.vectorCache[i].key, diccionario.vectorCache[i].nkey)) == 0); i++)
		;
	if (i < cacheSize / chunkSize)
		return 1;
	else
		return 0;
}
